﻿using Cms.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Linq;
using System.Diagnostics;
using Cms.Core.Infrastructure.Extension;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Application.IService;
using System.Threading;
using Cms.Core.Infrastructure.Ui;
using Microsoft.AspNetCore.Mvc;
using Cms.Core.Infrastructure.Log;
using Cms.Core.Infrastructure.Attributes;

namespace Cms.Core.AspNetMvc.Mvc.Filter
{
    public class AsyncAuditActionFilter : IAsyncActionFilter
    {

    
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var actionDescriptor = context.ActionDescriptor;
       
            var controllerAction = actionDescriptor as ControllerActionDescriptor;
            var methodInfo = controllerAction.MethodInfo;
            var displayAttribute = methodInfo.GetCustomAttributes<DisplayAttribute>()?.FirstOrDefault();
            var parameterFilterAttribute= methodInfo.GetCustomAttributes<ParameterFilterAttribute>()?.FirstOrDefault();

            var disableAuditingAttribute = controllerAction.MethodInfo.GetCustomAttributes<DisableAuditingAttribute>().FirstOrDefault();
            var controllerDisableAuditingAttribute = controllerAction.ControllerTypeInfo.GetCustomAttributes<DisableAuditingAttribute>().FirstOrDefault();

            if (disableAuditingAttribute.IsNotNull()|| controllerDisableAuditingAttribute.IsNotNull())
            {
                await next();
                return;
            }



            var loggerHelper = ServiceLocator.Instance.GetService<ILoggerHelper>();
            Exception exception =null;
            var stopwatch = Stopwatch.StartNew();
            try
            {

                var result = await next();

                //判断是AjaxResult类型并不是成功
                 exception= WebApiResult(result);
             
                if (result.Exception != null && !result.ExceptionHandled)
                {
                    exception =result.Exception;
                }
            }
            catch (Exception ex)
            {
                loggerHelper.Error(ex.Message,ex);
                exception = ex;
            }
            finally
            {
                stopwatch.Stop();
                var totalMilliseconds = stopwatch.Elapsed.TotalMilliseconds.AsTo<long>();

              
                 var auditService = ServiceLocator.Instance.GetService<IAuditService>();
                await auditService.AddAuditLogAsync(controllerAction.ControllerTypeInfo.AsType(), controllerAction.MethodInfo, totalMilliseconds, context.ActionArguments, parameterFilterAttribute?.GetParameterName(), displayAttribute?.DisplayName(), exception);

            }
        }


        private Exception WebApiResult(ActionExecutedContext context)
        {
            IActionResult result = context.Result;

            //根据实际需求进行具体实现
            Exception exception = null;
            var objectResult=  result as ObjectResult;
            if (!objectResult.IsNull())
            {
                var iresult = objectResult.Value.GetType().GetInterfaces().Any(o => o.FullName == typeof(IReturnResult).FullName);
                if (iresult)
                {
                    if (objectResult.Value is IReturnResult @return)
                    {
                        if (@return.Success == false)
                        {
                            return new Exception(@return.Message);
                        }
                        else
                        {
                            return exception;
                        }
                    }
                }
            }
            else if (result == null)
            {
                return exception;
            }
         

            context.Exception = new Exception("返回结果类型必须为AjaxResult、PageData！！");
        
            return exception;

        }
    }




}
